package com.saturday.data.scope.impl;

import com.alibaba.fastjson.JSON;
import com.saturday.common.exception.BusinessException;
import com.saturday.common.exception.UserContextLoseException;
import com.saturday.common.model.UserContext;
import com.saturday.common.support.UserContextHolder;
import com.saturday.data.scope.AbstractDataPermissionHandler;
import com.saturday.data.scope.annotation.DataColumn;
import com.saturday.data.scope.constants.AreaDataScopeConstants;
import com.saturday.data.scope.constants.DataScopeRuleConstants;
import com.saturday.data.scope.constants.SqlWhereRelationEnum;
import com.saturday.data.vo.AreaDataAuthVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class AreaDataPermissionHandler extends AbstractDataPermissionHandler {

    @Override
    protected boolean isExecute(String key) {
        return DataScopeRuleConstants.AREA_DATA_SCOPE_KEY.equals(key);
    }

    @Override
    public Expression getDataColumnWhereSql(Expression expression, DataColumn dataColumn) throws JSQLParserException {

        String[] names = dataColumn.names();
        String alias = dataColumn.alias();
        String ruleKey = dataColumn.dataRuleKey();

        if (!isExecute(ruleKey)) {
            return expression;
        }

        StringBuilder whereSql = new StringBuilder();

        List<AreaDataAuthVo> userAuthData = getUserAuthData(ruleKey);

        if (CollectionUtils.isEmpty(userAuthData)) {
            throw BusinessException.createException("未查询到数据权限配置，无法获取数据");
        }

        if (names != null && names.length > 0) {
            AndExpression andExpression = new AndExpression();
            andExpression.setLeftExpression(expression == null ? CCJSqlParserUtil.parseCondExpression("1=1") : expression);

            List<String> collect = Arrays.stream(names).collect(Collectors.toList());
            for (AreaDataAuthVo areaDataAuthVo : userAuthData) {
                String province = areaDataAuthVo.getProvince();
                boolean hasProvince = false;
                whereSql.append("(");
                if (collect.contains(AreaDataScopeConstants.PROVINCE_FIELD)) {
                    if (StringUtils.isNotEmpty(alias)) {
                        whereSql.append(alias).append(".");
                    }
                    whereSql.append(AreaDataScopeConstants.PROVINCE_FIELD).append("='").append(province).append("'");
                    hasProvince = true;
                }
                if (collect.contains(AreaDataScopeConstants.CITY_FIELD)) {
                    List<String> cities = areaDataAuthVo.getCities();
                    if (CollectionUtils.isNotEmpty(cities)) {
                        if (hasProvince) {
                            whereSql.append(" and ");
                        }
                        if (StringUtils.isNotEmpty(alias)) {
                            whereSql.append(alias).append(".");
                        }
                        whereSql.append(AreaDataScopeConstants.CITY_FIELD).append(" in (");
                        for (String city : cities) {
                            whereSql.append("'").append(city).append("',");
                        }
                        whereSql = whereSql.delete(whereSql.length() - 1, whereSql.length());
                        whereSql.append(") ");
                    }
                }
                whereSql.append(") OR ");
            }

            String sql = whereSql.substring(0, whereSql.lastIndexOf("OR") - 1);
            andExpression.setRightExpression(CCJSqlParserUtil.parseCondExpression(sql));
            return andExpression;
        } else {
            throw new BusinessException("数据权限未设置数据库条件属性");
        }

    }

    @Override
    protected Expression getDataColumnsWhereSql(Expression where, DataColumn[] dataColumns, SqlWhereRelationEnum[] sqlWhereRelationEnums) throws JSQLParserException {
        for (DataColumn dataColumn : dataColumns) {
            where = getDataColumnWhereSql(where, dataColumn);
        }

        return where;
    }

    private List<AreaDataAuthVo> getUserAuthData(String ruleKey) {
        UserContext userContext = UserContextHolder.get();
        if (null == userContext) {
            throw UserContextLoseException.createException();
        }
        Map<String, String> authData = userContext.getAuthData();
        if (MapUtils.isEmpty(authData)) {
            return null;
        }
        String authDataValue = authData.get(ruleKey);

        List<AreaDataAuthVo> areaDataAuthVos = JSON.parseArray(authDataValue, AreaDataAuthVo.class);
        return areaDataAuthVos;
    }

}
